using Sirenix.OdinInspector;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;

using System.IO;
using System.Collections;
using System;
using Pangoo.Common;
using UnityEngine.UIElements;



#if UNITY_EDITOR

using UnityEditor;
#endif

namespace MetaTable
{
    public abstract class MetaTableOverview : ScriptableObject, IMetaTableOverview
    {
        [ShowInInspector]
        public MetaTableConfig Config;


        [ShowInInspector]
        public string Namespace
        {
            get
            {
                if (Config != null)
                {
                    return Config.Namespace;
                }
                return null;
            }
        }

        public abstract string TableName { get; }

        public virtual string RowDirPath
        {
            get
            {
                return Path.Join(Config.StreamResScriptableObjectDir, TableName).ToPath();
            }
        }

        public string RowPath(string filename)
        {
            return Path.Join(RowDirPath, $"{filename}.asset").ToPath();
        }
#if UNITY_EDITOR
        public string FileName
        {
            get
            {
                DirectoryUtility.ExistsOrCreate(Config.StreamResScriptableObjectDir);
                var path = (Config.StreamResScriptableObjectDir + "/" + TableName + "Overview.asset").ToPath();
                Debug.Log($"fileName:{path}");
                return path;
            }
        }
#endif

        public abstract IReadOnlyList<MetaTableUnityRow> UnityBaseRows { get; }

        public IReadOnlyList<MetaTableRow> BaseRows
        {
            get
            {
                List<MetaTableRow> BaseRows = new List<MetaTableRow>();
                for (int i = 0; i < UnityBaseRows.Count; i++)
                {
                    var baseRow = UnityBaseRows[i]?.BaseRow;
                    if (baseRow != null)
                    {
                        BaseRows.Add(baseRow);
                    }

                }
                return BaseRows;
            }
        }

        MetaTableConfig IMetaTableOverview.MetaConfig
        {
            get
            {
                return Config;
            }
            set
            {
                Config = value;
            }
        }



        public MetaTableRow GetBaseRowByName(string name)
        {
            if (name.IsNullOrWhiteSpace())
            {
                return null;
            }
            foreach (var unityRow in UnityBaseRows)
            {
                if (name.Equals(unityRow.Name))
                {
                    return unityRow.BaseRow;
                }
            }
            return null;
        }

        public MetaTableRow GetBaseRowByUuid(string uuid)
        {
            if (uuid.IsNullOrWhiteSpace())
            {
                return null;
            }
            foreach (var unityRow in UnityBaseRows)
            {
                if (uuid.Equals(unityRow.Uuid))
                {
                    return unityRow.BaseRow;
                }
            }
            return null;
        }

        public MetaTableUnityRow GetUnityRowByName(string name)
        {
            if (name.IsNullOrWhiteSpace())
            {
                return null;
            }
            foreach (var unityRow in UnityBaseRows)
            {
                if (name.Equals(unityRow.Name))
                {
                    return unityRow;
                }
            }
            return null;
        }

        public MetaTableUnityRow GetUnityRowByUuid(string uuid)
        {
            if (uuid.IsNullOrWhiteSpace())
            {
                return null;
            }
            foreach (var unityRow in UnityBaseRows)
            {
                if (uuid.Equals(unityRow.Uuid))
                {
                    return unityRow;
                }
            }
            return null;
        }

        public T ToTable<T>() where T : MetaTableBase, new()
        {
            T table = new T();
            table.AddRows(BaseRows);
            return table;
        }

        [Button("生成运行时表")]
        public abstract MetaTableBase ToTable();


#if UNITY_EDITOR
        // public abstract void RemoveRow(string uuid);

        public abstract void RemoveByUuid(string uuid);

        public abstract void AddRow(MetaTableUnityRow unityRow);

        public abstract void AddBaseRow(MetaTableRow row);

        public abstract void UpdateRow(string uuid, MetaTableRow row);




        public static bool TupleContainsItem1(List<Tuple<string, string>> tuples, string item1)
        {
            if (tuples == null) return false;

            foreach (var val in tuples)
            {
                if (val.Item1.Equals(item1))
                {
                    return true;
                }
            }
            return false;
        }

        public static IEnumerable GetUuidDropdown(Type type, List<string> excludeUuids = null, List<Tuple<string, string>> AdditionalOptions = null, List<Tuple<string, string>> includeUuids = null)
        {
            if (!type.IsSubclassOf(typeof(MetaTableOverview)))
            {
                Debug.LogError("Get Overvie Type is not SubclassOf MetaTableOverview! In GetUuidDropdown");
                return null;
            }

            Dictionary<string, IMetaTableRow> addUuids = new();
            var ret = new ValueDropdownList<string>();
            if (AdditionalOptions != null)
            {
                foreach (var options in AdditionalOptions)
                {
                    ret.Add(options.Item1, options.Item2);
                }
            }
            var overviews = GetOverviews(type);
            foreach (var overview in overviews)
            {
                foreach (var row in overview.BaseRows)
                {
                    bool flag = includeUuids != null ? TupleContainsItem1(includeUuids, row.Uuid) : excludeUuids == null ? true : !excludeUuids.Contains(row.Uuid) ? true : false;
                    if (flag)
                    {
                        ret.Add($"{row.UuidShort}-{row.Name}", row.Uuid);
                        addUuids.Add(row.Uuid, row);
                    }
                }
            }


            if (includeUuids != null)
            {
                foreach (var uuid in includeUuids)
                {
                    if (!addUuids.ContainsKey(uuid.Item1))
                    {
                        ret.Add($"{uuid.Item1.ToShortUuid()}-[{uuid.Item2}]", uuid.Item1);
                    }
                }
            }

            return ret;

        }

        public static IEnumerable GetUuidDropdown<T>(List<string> excludeUuids = null, List<Tuple<string, string>> AdditionalOptions = null, List<Tuple<string, string>> includeUuids = null) where T : MetaTableOverview
        {

            return GetUuidDropdown(typeof(T), excludeUuids, AdditionalOptions, includeUuids);
        }

        public static List<R> GetUnityRows<T, R>() where T : MetaTableOverview where R : MetaTableUnityRow
        {
            var overviews = GetOverviews<T>();
            List<R> ret = new List<R>();
            foreach (var overview in overviews)
            {
                foreach (var row in overview.UnityBaseRows)
                {
                    ret.Add(row as R);
                }
            }

            return ret;
        }


        public class CachedOverview
        {
            public object data;

            public DateTime dateTime;
        }


        public readonly static Dictionary<Type, CachedOverview> OverviewCachedDict = new Dictionary<Type, CachedOverview>();

        static object GetOverviewsInternal(Type type)
        {
            if (type.IsSubclassOf(typeof(MetaTableOverview)))
            {
                var overviewAssets = AssetDatabaseUtility.FindAsset(type);
                if (overviewAssets == null) return null;

                // 先创建开放泛型
                Type listType = typeof(List<>);
                // 再创建具象泛型
                Type listInstanceType = listType.MakeGenericType(type);
                var originData = Activator.CreateInstance(listInstanceType);

                // 最后创建泛型实例
                IList result = (IList)originData;
                // List<MetaTableOverview> overviews = new List<MetaTableOverview>();
                foreach (var overview in overviewAssets)
                {
                    result.Add(overview);
                }
                return originData;
            }
            return null;
        }

        public static object GetOverviewByDict(Type type, bool notUseCache = false)
        {
            if (!type.IsSubclassOf(typeof(MetaTableOverview)))
            {
                Debug.LogError("Get Overvie Type is not SubclassOf MetaTableOverview!");
                return null;
            }

            var now = DateTime.Now;
            CachedOverview cached = null;
            if (OverviewCachedDict.TryGetValue(type, out cached) && !notUseCache)
            {
                if (cached.dateTime < (now + new TimeSpan(0, 0, 3)))
                {
                    return cached.data;
                }
            }
            else
            {
                cached = new CachedOverview();
                OverviewCachedDict.Add(type, cached);
            }

            cached.data = GetOverviewsInternal(type);
            cached.dateTime = now;
            return cached.data;
        }


        public static List<T> GetOverviews<T>(bool notUseCache = false) where T : MetaTableOverview
        {
            return GetOverviewByDict(typeof(T), notUseCache) as List<T>;
        }

        public static IEnumerable<MetaTableOverview> GetOverviews(Type type, bool notUseCache = false)
        {
            return GetOverviewByDict(type, notUseCache) as IEnumerable<MetaTableOverview>;
        }

        public static IEnumerable GetOverviewDropdown<T>(string packageDir = null) where T : MetaTableOverview
        {
            var ret = new ValueDropdownList<T>();
            var overviews = GetOverviews<T>();
            foreach (var overview in overviews)
            {
                ret.Add(overview.Namespace, overview);
            }

            return ret;
        }


        public static R GetUnityRowByUuid<T, R>(string uuid) where T : MetaTableOverview where R : MetaTableUnityRow
        {
            if (uuid.IsNullOrWhiteSpace()) return null;
            var overviews = GetOverviews<T>();
            foreach (var overview in overviews)
            {
                foreach (var row in overview.UnityBaseRows)
                {
                    if (row.Uuid.NullEquals(uuid))
                    {
                        return row as R;
                    }

                }
            }
            return null;
        }

        public static T GetOverviewByUuid<T>(string uuid) where T : MetaTableOverview
        {
            if (uuid.IsNullOrWhiteSpace()) return null;
            var overviews = GetOverviews<T>();
            foreach (var overview in overviews)
            {

                foreach (var row in overview.UnityBaseRows)
                {
                    if (row.Uuid.NullEquals(uuid))
                    {
                        return overview;
                    }

                }
            }
            return null;
        }




        public T AddRow<T>(MetaTableUnityRow unityRow = null) where T : MetaTableUnityRow
        {
            if (unityRow == null)
            {
                unityRow = ScriptableObject.CreateInstance<T>();
                var newUuid = UuidUtility.GetNewUuid();
                unityRow.BaseRow.Uuid = newUuid;
            }

            DirectoryUtility.ExistsOrCreate(RowDirPath);
            string dest = RowPath(unityRow.BaseRow.Uuid);
            AssetDatabase.CreateAsset(unityRow, dest);
            AssetDatabase.SaveAssets();
            return unityRow as T;
        }


        public abstract void RefreshRows();

        public List<T> RefreshRows<T>() where T : MetaTableUnityRow
        {
            List<T> ret = new List<T>();
            var rowList = AssetDatabaseUtility.FindAsset<T>(RowDirPath);
            Debug.Log($"rowList:{rowList}, {rowList?.Count()}");
            foreach (var row in rowList)
            {
                ret.Add(row as T);
            }
            return ret;
        }


        [Button("保存配置", 30)]
        public void SaveConfig()
        {
            EditorUtility.SetDirty(this);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            // GUIUtility.ExitGUI();
        }

        public void Save()
        {
            SaveConfig();
        }

#endif
    }
}

